#include "aerStackAllocator.hpp"


namespace aer {

  
void* StackAllocator::allocate(const U32 byteSize)
{
  if (m_top + byteSize > m_byteSize) {
    return NULL;
  }
  void *pData = (UPTR*)(m_data) + m_top;
  m_top += byteSize;
  return pData;
}

void* StackAllocator::allocateAligned(const U32 byteSize, const U32 alignment)
{
  // Handles only alignment of power of two greater than 2
  AER_ASSERT( alignment > 2 );
  //AER_ASSERT( IsPowerOfTwo(alignment) );
  
  // Total amount of memory to allocate
  U32 expandedSize = byteSize + alignment;
  
  // Allocate an unaligned block and convert the address
  UPTR rawAddress = UPTR( allocate(expandedSize) );
  
  if (rawAddress == 0) {
    return NULL;
  }
  
  // Calculates the adjustment by masking off the lower bits of the address
  UPTR mask = (alignment - 1u);
  UPTR misalignment = (rawAddress & mask);
  UPTR adjustment = alignment - misalignment;
  
  // Calculate the adjusted address
  UPTR alignedAddress = rawAddress + adjustment;
  m_top += adjustment;
  
  // Store the adjustment in the four bytes preceding the adjusted address
  // returned
  UPTR *pAdjustment = (UPTR*)(alignedAddress - 4u);
  *pAdjustment = adjustment;
  
  return (void*)alignedAddress;
}   

void StackAllocator::freeToMarker(const Marker marker) 
{ 
  AER_ASSERT( marker < m_top );  
  m_top = marker; 
}

void StackAllocator::freeAlignedToMarker(const Marker marker) 
{ 
  AER_ASSERT( (marker >= 4) && (marker < m_top) );
  
  UPTR adjustment = ((UPTR*)m_data)[marker-4];  
  Marker rawMarker = marker - adjustment;
  
  freeToMarker( rawMarker );
}
  
} // aer
